import tkinter as tk  # tkinter是Python内置的GUI库,用于创建图形用户界面
from tkinter import filedialog  # filedialog是tkinter中的一个模块,用于显示文件对话框
from tkinter import messagebox  # messagebox是tkinter中的一个模块,用于显示消息框
from PIL import Image, ImageTk  # PIL是Python的图像处理库,用于加载、操作和保存图像
import os  # os模块提供了与操作系统交互的功能,如文件路径操作
import numpy as np  # numpy是Python的数值计算库,用于处理数组和矩阵
import image_channels  # image_channels是一个自定义模块,用于分割和合并图像通道
import image_io  # image_io是一个自定义模块,用于加载和保存图像
import image_transform  # image_transform是一个自定义模块,用于图像变换
from tkinter import ttk  # ttk是tkinter的一个子模块,提供了更美观的GUI组件
import config  # config是一个自定义模块,用于存储应用程序的配置信息
import sys  # sys模块提供了与Python解释器和运行环境相关的变量和函数
from image_utils import language_data, logging  # 从image_utils模块中导入language_data和logging
import image_utils as utils  # 导入image_utils模块并给它一个别名utils
import subprocess  # subprocess模块允许你生成新的进程，连接它们的输入、输出和错误管道，并获取它们的返回码


class ImageProcessor:
    def __init__(self, master):
        """初始化ImageProcessor类的实例"""
        self.master = master  # 主窗口
        self.current_language = language_data["current_language"]  # 默认语言通过JSON文件直接设置
        master.title(language_data[self.current_language]['app_title'])  # 设置初始窗口标题        self.image = None  # 用于存储当前图像的numpy数组
        self.image_path = ""  # 用于存储当前图像的文件路径
        self.current_mask = None  # 用于存储当前生成的掩模
        self.rect_start_x = None  # 用于存储裁剪矩形框起始点的x坐标
        self.rect_start_y = None  # 用于存储裁剪矩形框起始点的y坐标python main.py        python main.py        python main.py        python main.py        python main.py
        self.rect_end_x = None  # 用于存储裁剪矩形框结束点的x坐标
        self.rect_end_y = None  # 用于存储裁剪矩形框结束点的y坐标
        self.is_drawing = False  # 用于标记是否正在绘制裁剪矩形框
        self.current_rect = None  # 用于存储当前绘制的裁剪矩形框对象

        self.create_widgets()  # 创建GUI组件

    def create_widgets(self):
        """创建GUI组件"""
        # 创建菜单栏
        menubar = tk.Menu(self.master)
        self.master.config(menu=menubar)

        # 创建文件菜单
        file_menu = tk.Menu(menubar)
        file_menu.add_command(label=language_data[self.current_language]['open_original'], command=self.Open_as_original)
        file_menu.add_command(label=language_data[self.current_language]['open_grayscale'], command=self.Open_as_gray)
        file_menu.add_command(label=language_data[self.current_language]['merge_channels'], command=self.merge_channels)
        file_menu.add_command(label=language_data[self.current_language]['save_image'], command=self.save_image)
        file_menu.add_separator()
        
        # 创建一个菜单项,用于切换语言,它应该有两个子菜单项,分别用于切换中文和英文。当前语言用一个勾选标记来表示。
        language_menu = tk.Menu(file_menu)
        self.language_var = tk.StringVar(value=self.current_language)
        language_menu.add_radiobutton(label="中文", variable=self.language_var, value="zh", command=self.change_language)
        language_menu.add_radiobutton(label="English", variable=self.language_var, value="en", command=self.change_language)
        file_menu.add_cascade(label=language_data[self.current_language]['language'], menu=language_menu)
        
        file_menu.add_command(label=language_data[self.current_language]['exit'], command=self.master.quit)
        menubar.add_cascade(label=language_data[self.current_language]['file'], menu=file_menu)

        # 创建信息菜单
        info_menu = tk.Menu(menubar)
        info_menu.add_command(label=language_data[self.current_language]['details'], command=self.show_image_details)
        menubar.add_cascade(label=language_data[self.current_language]['info'], menu=info_menu)        # 创建编辑菜单
        edit_menu = tk.Menu(menubar)
        edit_menu.add_command(label=language_data[self.current_language]['crop'], command=self.crop_image)
        edit_menu.add_command(label=language_data[self.current_language]['reset'], command=self.reset_image)
        edit_menu.add_command(label=language_data[self.current_language]['adjust_contrast'], command=self.show_contrast_window)
        edit_menu.add_command(label=language_data[self.current_language]['adjust_brightness'], command=self.show_brightness_window)
        menubar.add_cascade(label=language_data[self.current_language]['edit'], menu=edit_menu)        # 创建图像分割菜单
        split_menu = tk.Menu(menubar)
        menubar.add_cascade(label=language_data[self.current_language]['split'], menu=split_menu)
        split_menu.add_command(label=language_data[self.current_language]['split_channels'], command=self.split_image_channels)
          # 创建阈值处理菜单
        threshold_menu = tk.Menu(menubar)
        menubar.add_cascade(label=language_data[self.current_language]['threshold'], menu=threshold_menu)
        threshold_menu.add_command(label=language_data[self.current_language]['global_threshold'], command=self.show_global_threshold_window)
        
        # 创建边缘处理菜单
        edge_menu = tk.Menu(menubar)
        menubar.add_cascade(label=language_data[self.current_language]['edge'], menu=edge_menu)
        edge_menu.add_command(label=language_data[self.current_language]['shift_difference'], command=self.show_shift_difference_window)
        
        # 创建位运算菜单
        bitwise_menu = tk.Menu(menubar)
        menubar.add_cascade(label=language_data[self.current_language]['bitwise'], menu=bitwise_menu)
        bitwise_menu.add_command(label=language_data[self.current_language]['bitwise_not'], command=self.apply_invert_colors)
          # 创建掩模菜单
        mask_menu = tk.Menu(menubar)
        menubar.add_cascade(label=language_data[self.current_language]['mask'], menu=mask_menu)
          # 创建生成掩模子菜单
        create_mask_menu = tk.Menu(mask_menu)
        mask_menu.add_cascade(label=language_data[self.current_language]['create_mask'], menu=create_mask_menu)
        create_mask_menu.add_command(label=language_data[self.current_language]['red_mask'], command=self.create_red_mask)
        create_mask_menu.add_command(label=language_data[self.current_language]['green_mask'], command=self.create_green_mask)
        create_mask_menu.add_command(label=language_data[self.current_language]['blue_mask'], command=self.create_blue_mask)
        
        # 创建应用掩模子菜单
        mask_menu.add_command(label=language_data[self.current_language]['apply_and'], command=self.apply_mask_and)
        mask_menu.add_command(label=language_data[self.current_language]['apply_not'], command=self.apply_mask_not)
        mask_menu.add_command(label=language_data[self.current_language]['apply_or'], command=self.apply_mask_or)
        mask_menu.add_command(label=language_data[self.current_language]['apply_xor'], command=self.apply_mask_xor)

        # 创建图像显示区域
        self.canvas = tk.Canvas(self.master, width=600, height=400)
        self.canvas.pack()

        self.canvas.bind("<Button-1>", self.on_mouse_down)
        self.canvas.bind("<B1-Motion>", self.on_mouse_move)
        self.canvas.bind("<ButtonRelease-1>", self.on_mouse_up)
    
    def change_language(self):
        """切换语言"""
        # 把language.json文件中的current_language的值改为当前的self.current_language
        self.current_language = self.language_var.get()  # 获取所选择的语言
        utils.write_language_data(language_data, "current_language", self.current_language)
        logging.info(f"当前语言已切换为{self.current_language}。")
        confirm = messagebox.askyesno(language_data[self.current_language]['confirm_restart'],
                                  language_data[self.current_language]['restart_warning'])
        if confirm:
            self.master.destroy()
            # os.execl(sys.executable, sys.executable, *sys.argv)
            subprocess.Popen([sys.executable] + sys.argv)

    def merge_channels(self):
        """合并多个单通道图像为一个多通道图像"""
        # 打开文件对话框,让用户选择多个图像文件
        file_paths = filedialog.askopenfilenames()
        # 如果用户没有选择文件,直接返回
        if not file_paths:
            return
        
        # 如果只选择了一个文件,显示错误信息并返回
        if len(file_paths) == 1:
            tk.messagebox.showerror(language_data[self.current_language]['error'], language_data[self.current_language]['single_file_error'])
            return
        
        try:
            self.image = image_channels.merge_image_channels(file_paths)
        except ValueError as e:
            tk.messagebox.showerror(language_data[self.current_language]['error'], str(e))
            return
        
        # 显示当前图像
        self.display_image()

    def split_image_channels(self):
        """分割当前图像的通道,并在新窗口中显示每个通道"""
        if self.image is None:
            tk.messagebox.showinfo(language_data[self.current_language]['error'], language_data[self.current_language]['no_image_loaded'])
            return

        if len(self.image.shape) == 2:
            tk.messagebox.showinfo(language_data[self.current_language]['error'], language_data[self.current_language]['single_channel_error'])
            return

        try:
            channels = image_channels.split_image_channels(self.image)
        except ValueError as e:
            tk.messagebox.showinfo(language_data[self.current_language]['error'], str(e))
            return
        
        for i, channel in enumerate(channels):
            window = tk.Toplevel(self.master)
            window.title(language_data[self.current_language]['channel_title'].format(i))
            canvas = tk.Canvas(window, width=300, height=300)
            canvas.pack()

            # 定义内部函数用于保存单个通道
            def save_channel(channel, index):
                save_path = filedialog.asksaveasfilename(defaultextension=config.DEFAULT_SAVE_FORMAT)
                if not save_path:
                    return
                image_io.save_image(channel, save_path)
                tk.messagebox.showinfo(language_data[self.current_language]['success'], language_data[self.current_language]['channel_saved'].format(index, save_path))
            
            save_button = tk.Button(window, text=language_data[self.current_language]['save_channel'], command=lambda channel=channel: save_channel(channel, i))
            save_button.pack()

            window.update()

            # 显示子通道图像
            image = Image.fromarray(channel)  # 将通道数据转换为PIL图像对象
            canvas_width = canvas.winfo_width()  # 获取画布的宽度
            canvas_height = canvas.winfo_height()  # 获取画布的高度
            image_width, image_height = image.size  # 获取图像的宽度和高度
            scale = min(canvas_width / image_width, canvas_height / image_height)  # 计算图像的缩放比例
            if scale < 1:  # 如果图像过大,缩小图像
                new_width = int(image_width * scale)
                new_height = int(image_height * scale)
                image = image.resize((new_width, new_height), Image.LANCZOS)  # 使用Lanczos滤波器进行缩小
            else:  # 如果图像过小,放大图像
                new_width = int(image_width * scale)
                new_height = int(image_height * scale)
                image = image.resize((new_width, new_height), Image.BICUBIC)  # 使用双三次滤波器进行放大

            photo = ImageTk.PhotoImage(image)  # 将PIL图像对象转换为PhotoImage对象
            x = (canvas_width - new_width) // 2  # 计算图像在画布上的水平居中位置
            y = (canvas_height - new_height) // 2  # 计算图像在画布上的垂直居中位置
            canvas.create_image(x, y, anchor=tk.NW, image=photo)  # 在画布上显示图像
            canvas.image = photo  # 将PhotoImage对象保存到画布中,防止被垃圾回收

            # 在子图上添加清晰的标题
            title = f"Channel {i}"
            canvas.create_text(canvas_width//2, 15, text=title, font=("Arial", 15), fill="black")

        logging.info("图像分割操作成功。")  # 记录成功日志

    def show_image_details(self):
        """显示当前图像的详细信息"""
        if self.image is None:  # 如果当前没有图像,显示相应消息并返回
            messagebox.showinfo(language_data[self.current_language]['error'], language_data[self.current_language]['no_image_loaded'])
            logging.info("没有载入任何图像,无法显示图像细节。")  # 记录日志信息
            return

        # 从路径中提取文件名
        filename = os.path.basename(self.image_path)        # 计算其他基本信息
        total_pixels = self.image.size  # TODO: 获取图像的总像素数
        shape = self.image.shape  # TODO: 获取图像的形状(高度,宽度,通道数)
        channels = 1 if len(self.image.shape) == 2 else self.image.shape[2]  # TODO: 获取图像的通道数，注意不是维度，而是通道数
        dtype = self.image.dtype  # TODO: 获取图像像素的数据类型

        # 构建信息字符串,包括文件名
        details = language_data[self.current_language]['info_str'].format(filename,total_pixels,shape,channels,dtype)

        # 显示信息
        messagebox.showinfo("INFO", details)
        logging.info("已显示图像细节。")  # 记录成功日志

    def on_mouse_down(self, event):
        """处理鼠标左键按下事件"""
        if self.current_rect and not self.is_drawing:
            # 如果存在矩形框且不是在拖动状态,删除矩形框并重置状态
            self.canvas.delete(self.current_rect)
            self.current_rect = None
        else:
            # 否则,开始绘制新的矩形框
            self.rect_start_x = event.x
            self.rect_start_y = event.y
            self.is_drawing = True

    def on_mouse_move(self, event):
        """处理鼠标左键移动事件"""
        if self.is_drawing:
            if self.current_rect:
                self.canvas.delete(self.current_rect)
            self.current_rect = self.canvas.create_rectangle(self.rect_start_x, self.rect_start_y, event.x, event.y, outline="red")

    def on_mouse_up(self, event):
        """处理鼠标左键释放事件"""
        # 标记矩形的结束点并完成绘制
        self.rect_end_x, self.rect_end_y = event.x, event.y
        self.is_drawing = False
        # 保存裁剪区域的坐标
        self.crop_region = (min(self.rect_start_y, self.rect_end_y), max(self.rect_start_y, self.rect_end_y),
                            min(self.rect_start_x, self.rect_end_x), max(self.rect_start_x, self.rect_end_x))
        logging.info("已绘制裁剪区域。")  # 记录成功日志

    def Open_as_original(self):
        """打开原始图像"""
        logging.info("正在打开原始图像...") 
        self.image_path = filedialog.askopenfilename()  # 打开文件对话框,让用户选择图像文件
        if not self.image_path:
            logging.info("没有选择任何图像文件,打开操作已取消。")  # 记录日志信息
            return  # 如果没有选择任何文件,直接返回
        self.image = image_io.load_image(self.image_path)  # 加载图像文件
        self.display_image()  # 显示图像
        logging.info("成功打开原始图像。")  # 记录成功日志
    
    def Open_as_gray(self):
        """将原始图像转换为灰度图像"""
        self.image_path = filedialog.askopenfilename()  # 打开文件对话框,让用户选择图像文件
        if not self.image_path:
            logging.info("没有选择任何图像文件,打开操作已取消。")  # 记录日志信息
            return  # 如果没有选择任何文件,直接返回
        self.image = image_io.load_image(self.image_path, as_gray=True)  # 加载图像文件并转换为灰度图像
        self.display_image()  # 显示图像
        logging.info("成功打开并转换为灰度图像。")  # 记录成功日志

    def display_image(self):
        """在主画布上显示当前图像"""
        if self.image is None:
            logging.info("当前没有图像可显示。")  # 记录日志信息
            return  # 如果当前没有图像,直接返回

        image = Image.fromarray(self.image)  # 将numpy数组转换为PIL图像对象

        # 计算图像的缩放比例
        canvas_width = self.canvas.winfo_width()  # 获取画布的宽度
        canvas_height = self.canvas.winfo_height()  # 获取画布的高度
        image_width, image_height = image.size  # 获取图像的宽度和高度
        scale = min(canvas_width / image_width, canvas_height / image_height)  # 计算图像的缩放比例

        # 缩放图像
        if scale < 1:
            # 图像过大,缩小图像
            new_width = int(image_width * scale)
            new_height = int(image_height * scale)
            image = image.resize((new_width, new_height), Image.LANCZOS)  # 使用Lanczos滤波器进行缩小
        else:
            # 图像过小,放大图像
            new_width = int(image_width * scale)
            new_height = int(image_height * scale)
            image = image.resize((new_width, new_height), Image.BICUBIC)  # 使用双三次滤波器进行放大

        photo = ImageTk.PhotoImage(image)  # 将PIL图像对象转换为PhotoImage对象
        self.canvas.delete("all")  # 清除画布上的所有内容

        # 计算图像在画布上的居中位置
        x = (canvas_width - new_width) // 2
        y = (canvas_height - new_height) // 2
        self.canvas.create_image(x, y, anchor=tk.NW, image=photo)  # 在画布上显示图像, tk.NW表示图像的左上角对齐画布的左上角
        self.canvas.image = photo  # 将PhotoImage对象保存到画布中,防止被垃圾回收
        logging.info("成功显示图像。")  # 记录成功日志

    def save_image(self):
        """保存当前图像"""
        if self.image is None:
            tk.messagebox.showinfo(language_data[self.current_language]['error'], language_data[self.current_language]['no_image_to_be_saved'])
            logging.error("没有图像可保存,保存操作已取消。")  # 记录错误日志
            return  # 如果当前没有图像,直接返回

        save_path = filedialog.asksaveasfilename(defaultextension=config.DEFAULT_SAVE_FORMAT)  # 打开保存文件对话框
        if not save_path:
            logging.info("没有选择保存路径,保存操作已取消。")  # 记录日志信息
            return  # 如果没有选择保存路径,直接返回

        image_io.save_image(self.image, save_path)  # 将当前图像保存到指定路径
        logging.info(f"图像已成功保存到 {save_path}。")  # 记录成功日志

    def crop_image(self):
        """裁剪当前图像"""
        if self.image is None:
            tk.messagebox.showinfo(language_data[self.current_language]['error'], language_data[self.current_language]['no_image_to_be_cropped'])
            logging.error("没有图像可裁剪,裁剪操作已取消。")  # 记录错误日志
            return  # 如果当前没有图像,直接返回

        # 检查是否有绘制的裁剪区域
        if hasattr(self, 'crop_region') and self.current_rect:
            # 计算实际裁剪区域坐标(考虑图像缩放和偏移)
            image_height, image_width = self.image.shape[:2]  # 获取图像的高度和宽度
            canvas_width = self.canvas.winfo_width()  # 获取画布的宽度
            canvas_height = self.canvas.winfo_height()  # 获取画布的高度
            scale = min(canvas_width / image_width, canvas_height / image_height)  # 计算图像的缩放比例
            offset_x = (canvas_width - image_width * scale) // 2  # 计算图像在画布上的水平偏移量
            offset_y = (canvas_height - image_height * scale) // 2  # 计算图像在画布上的垂直偏移量

            # 计算实际裁剪区域坐标
            real_crop_region = (
                int((self.crop_region[0] - offset_y) / scale),
                int((self.crop_region[1] - offset_y) / scale),
                int((self.crop_region[2] - offset_x) / scale),
                int((self.crop_region[3] - offset_x) / scale)
            )

            cropped_image = image_transform.crop_image(self.image, real_crop_region)  # 裁剪图像
            if cropped_image is not None:
                self.image = cropped_image  # 将裁剪后的图像保存到self.image中
                self.display_image()  # 显示裁剪后的图像
                logging.info("图像裁剪成功。")  # 记录成功日志

                # 清零裁剪框信息
                self.canvas.delete(self.current_rect)  # 删除画布上的裁剪矩形框
                self.current_rect = None  # 将当前裁剪矩形框对象设置为None
                del self.crop_region  # 删除存储裁剪区域坐标的属性
            else:
                tk.messagebox.showinfo(language_data[self.current_language]['error'], language_data[self.current_language]['crop_failed'])
                logging.error("裁剪操作失败。")  # 记录错误日志
        else:
            tk.messagebox.showinfo(language_data[self.current_language]['error'], language_data[self.current_language]['no_crop_area'])
            logging.error("没有选择裁剪区域,裁剪操作已取消。")  # 记录错误日志
            
    def reset_image(self):
        """重置当前图像为原始状态"""
        if not self.image_path:  # 如果没有图像路径,显示错误消息并返回
            tk.messagebox.showinfo(language_data[self.current_language]['error'], language_data[self.current_language]['no_reset_image'])
            logging.error("没有图像可重置,重置操作已取消。")  # 记录错误日志
            return
        self.image = image_io.load_image(self.image_path)  # 重新加载图像
        self.display_image()  # 显示图像
        logging.info("图像已重置为原始状态。")  # 记录成功日志
    
    def show_contrast_window(self):
        """显示对比度调整窗口"""
        if not hasattr(self, 'image') or self.image is None:
            tk.messagebox.showinfo(language_data[self.current_language]['error'], 
                                 language_data[self.current_language]['no_image_to_adjust'])
            logging.error("没有图像可调整对比度,操作已取消。")
            return
            
        # 创建一个新窗口
        contrast_window = tk.Toplevel(self.master)
        contrast_window.title(language_data[self.current_language]['adjust_contrast'])
        contrast_window.geometry("600x500")
        contrast_window.resizable(False, False)
        
        # 保存原始图像的副本，用于预览
        self.original_image_for_contrast = self.image.copy()
        
        # 创建对比度滑动条框架
        slider_frame = tk.Frame(contrast_window)
        slider_frame.pack(pady=10)
        
        # 创建对比度滑动条标签
        tk.Label(slider_frame, text=language_data[self.current_language]['contrast']).pack(side=tk.LEFT, padx=5)
        
        # 创建对比度值标签，用于显示当前对比度值
        contrast_value_label = tk.Label(slider_frame, text="1.0")
        contrast_value_label.pack(side=tk.RIGHT, padx=5)
        
        # 创建对比度滑动条
        contrast_slider = ttk.Scale(
            slider_frame, 
            from_=0.1, 
            to=3.0, 
            value=1.0,
            length=300,
            orient=tk.HORIZONTAL
        )
        contrast_slider.pack(side=tk.LEFT, padx=5)
        
        # 创建预览画布
        preview_canvas = tk.Canvas(contrast_window, width=500, height=350)
        preview_canvas.pack(pady=10)
        
        # 创建确认和取消按钮框架
        button_frame = tk.Frame(contrast_window)
        button_frame.pack(pady=10)
        
        # 预览图像函数
        def preview_contrast(event=None):
            contrast_factor = contrast_slider.get()
            contrast_value_label.config(text=f"{contrast_factor:.1f}")
            
            # 使用图像处理函数调整对比度
            preview_image = image_transform.adjust_contrast(self.original_image_for_contrast, contrast_factor)
            
            # 显示预览图像
            self._display_image_on_canvas(preview_image, preview_canvas)
        
        # 应用对比度调整
        def apply_contrast():
            contrast_factor = contrast_slider.get()
            self.image = image_transform.adjust_contrast(self.original_image_for_contrast, contrast_factor)
            self.display_image()  # 更新主窗口显示
            contrast_window.destroy()  # 关闭调整窗口
            logging.info(f"已应用对比度调整，对比度因子：{contrast_factor}")
        
        # 取消对比度调整
        def cancel_contrast():
            contrast_window.destroy()  # 关闭调整窗口
            logging.info("已取消对比度调整")
        
        # 滑动条值变化时预览图像
        contrast_slider.bind("<Motion>", preview_contrast)
        
        # 创建确认和取消按钮
        tk.Button(button_frame, text=language_data[self.current_language]['apply'], command=apply_contrast).pack(side=tk.LEFT, padx=10)
        tk.Button(button_frame, text=language_data[self.current_language]['cancel'], command=cancel_contrast).pack(side=tk.LEFT, padx=10)
        
        # 初始预览
        preview_contrast()
    
    def show_brightness_window(self):
        """显示亮度调整窗口"""
        if not hasattr(self, 'image') or self.image is None:
            tk.messagebox.showinfo(language_data[self.current_language]['error'], 
                                language_data[self.current_language]['no_image_to_adjust'])
            logging.error("没有图像可调整亮度,操作已取消。")
            return
            
        # 创建一个新窗口
        brightness_window = tk.Toplevel(self.master)
        brightness_window.title(language_data[self.current_language]['adjust_brightness'])
        brightness_window.geometry("600x500")
        brightness_window.resizable(False, False)
        
        # 保存原始图像的副本，用于预览
        self.original_image_for_brightness = self.image.copy()
        
        # 创建亮度滑动条框架
        slider_frame = tk.Frame(brightness_window)
        slider_frame.pack(pady=10)
        
        # 创建亮度滑动条标签
        tk.Label(slider_frame, text=language_data[self.current_language]['brightness']).pack(side=tk.LEFT, padx=5)
        
        # 创建亮度值标签，用于显示当前亮度值
        brightness_value_label = tk.Label(slider_frame, text="100%")
        brightness_value_label.pack(side=tk.RIGHT, padx=5)
        
        # 创建亮度滑动条
        brightness_slider = ttk.Scale(
            slider_frame, 
            from_=0.0, 
            to=2.0, 
            value=1.0,
            length=300,
            orient=tk.HORIZONTAL
        )
        brightness_slider.pack(side=tk.LEFT, padx=5)
        
        # 创建预览画布
        preview_canvas = tk.Canvas(brightness_window, width=500, height=350)
        preview_canvas.pack(pady=10)
        
        # 创建确认和取消按钮框架
        button_frame = tk.Frame(brightness_window)
        button_frame.pack(pady=10)
        
        # 预览图像函数
        def preview_brightness(event=None):
            brightness_factor = brightness_slider.get()
            # 将浮点数转换为百分比显示
            brightness_percentage = int(brightness_factor * 100)
            brightness_value_label.config(text=f"{brightness_percentage}%")
            
            # 使用图像处理函数调整亮度
            preview_image = image_transform.adjust_brightness(self.original_image_for_brightness, brightness_factor)
            
            # 显示预览图像
            self._display_image_on_canvas(preview_image, preview_canvas)
        
        # 应用亮度调整
        def apply_brightness():
            brightness_factor = brightness_slider.get()
            self.image = image_transform.adjust_brightness(self.original_image_for_brightness, brightness_factor)
            self.display_image()  # 更新主窗口显示
            brightness_window.destroy()  # 关闭调整窗口
            logging.info(f"已应用亮度调整，亮度因子：{brightness_factor}")
        
        # 取消亮度调整
        def cancel_brightness():
            brightness_window.destroy()  # 关闭调整窗口
            logging.info("已取消亮度调整")
        
        # 滑动条值变化时预览图像
        brightness_slider.bind("<Motion>", preview_brightness)
        
        # 创建确认和取消按钮
        tk.Button(button_frame, text=language_data[self.current_language]['apply'], command=apply_brightness).pack(side=tk.LEFT, padx=10)
        tk.Button(button_frame, text=language_data[self.current_language]['cancel'], command=cancel_brightness).pack(side=tk.LEFT, padx=10)
        
        # 初始预览
        preview_brightness()
    
    def _display_image_on_canvas(self, image, canvas):
        """在指定画布上显示图像"""
        from PIL import Image, ImageTk
        import numpy as np
        
        if image is None:
            return
            
        # 将numpy数组转换为PIL图像
        if isinstance(image, np.ndarray):
            if image.dtype != np.uint8:
                image = image.astype(np.uint8)
            pil_image = Image.fromarray(image)
        else:
            pil_image = image
            
        # 调整图像大小以适应画布
        canvas_width = canvas.winfo_width()
        canvas_height = canvas.winfo_height()
        
        # 确保画布尺寸有效
        if canvas_width <= 1 or canvas_height <= 1:
            canvas_width = 500
            canvas_height = 350
            
        # 计算缩放比例
        img_width, img_height = pil_image.size
        scale = min(canvas_width / img_width, canvas_height / img_height)
        
        # 缩放图像
        new_width = int(img_width * scale)
        new_height = int(img_height * scale)
        resized_image = pil_image.resize((new_width, new_height), Image.LANCZOS)
        
        # 转换为PhotoImage
        photo = ImageTk.PhotoImage(resized_image)
        
        # 清除画布并显示图像
        canvas.delete("all")
        canvas.create_image(canvas_width // 2, canvas_height // 2, image=photo, anchor=tk.CENTER)
        
        # 保持对PhotoImage的引用防止被垃圾回收
        canvas.image = photo

    def show_global_threshold_window(self):
        """显示全局阈值处理窗口"""
        if not hasattr(self, 'image') or self.image is None:
            tk.messagebox.showinfo(language_data[self.current_language]['error'], 
                                language_data[self.current_language]['no_image_to_adjust'])
            logging.error("没有图像可进行阈值处理，操作已取消。")
            return
        
        # 检查是否为灰度图像
        if len(self.image.shape) > 2 and self.image.shape[2] > 1:
            tk.messagebox.showinfo(language_data[self.current_language]['error'], 
                                language_data[self.current_language]['not_grayscale_error'])
            logging.error("尝试对非灰度图像应用阈值处理，操作已取消。")
            return
            
        # 创建一个新窗口
        threshold_window = tk.Toplevel(self.master)
        threshold_window.title(language_data[self.current_language]['global_threshold'])
        threshold_window.geometry("600x500")
        threshold_window.resizable(False, False)
        
        # 保存原始图像的副本，用于预览
        self.original_image_for_threshold = self.image.copy()
        
        # 创建阈值滑动条框架
        slider_frame = tk.Frame(threshold_window)
        slider_frame.pack(pady=10)
        
        # 创建阈值滑动条标签
        tk.Label(slider_frame, text=language_data[self.current_language]['threshold_value']).pack(side=tk.LEFT, padx=5)
        
        # 创建阈值值标签，用于显示当前阈值
        threshold_value_label = tk.Label(slider_frame, text="128")
        threshold_value_label.pack(side=tk.RIGHT, padx=5)
        
        # 创建阈值滑动条
        threshold_slider = ttk.Scale(
            slider_frame, 
            from_=0, 
            to=255, 
            value=128,  # 初始阈值设为128
            length=300,
            orient=tk.HORIZONTAL
        )
        threshold_slider.pack(side=tk.LEFT, padx=5)
        
        # 创建预览画布
        preview_canvas = tk.Canvas(threshold_window, width=500, height=350)
        preview_canvas.pack(pady=10)
        
        # 创建确认和取消按钮框架
        button_frame = tk.Frame(threshold_window)
        button_frame.pack(pady=10)
        
        # 预览图像函数
        def preview_threshold(event=None):
            threshold_value = int(threshold_slider.get())
            threshold_value_label.config(text=str(threshold_value))
            
            # 使用图像处理函数应用全局阈值
            preview_image = image_transform.apply_global_threshold(self.original_image_for_threshold, threshold_value)
            
            # 显示预览图像
            self._display_image_on_canvas(preview_image, preview_canvas)
        
        # 应用阈值处理
        def apply_threshold():
            threshold_value = int(threshold_slider.get())
            self.image = image_transform.apply_global_threshold(self.original_image_for_threshold, threshold_value)
            self.display_image()  # 更新主窗口显示
            threshold_window.destroy()  # 关闭调整窗口
            logging.info(f"已应用全局阈值处理，阈值：{threshold_value}")
        
        # 取消阈值处理
        def cancel_threshold():
            threshold_window.destroy()  # 关闭调整窗口
            logging.info("已取消全局阈值处理")
        
        # 滑动条值变化时预览图像
        threshold_slider.bind("<Motion>", preview_threshold)
        
        # 创建确认和取消按钮
        tk.Button(button_frame, text=language_data[self.current_language]['apply'], command=apply_threshold).pack(side=tk.LEFT, padx=10)
        tk.Button(button_frame, text=language_data[self.current_language]['cancel'], command=cancel_threshold).pack(side=tk.LEFT, padx=10)
        
        # 初始预览
        preview_threshold()

    def show_shift_difference_window(self):
        """显示移动差分边缘检测窗口"""
        if not hasattr(self, 'image') or self.image is None:
            tk.messagebox.showinfo(language_data[self.current_language]['error'], 
                                language_data[self.current_language]['no_image_to_adjust'])
            logging.error("没有图像可进行移动差分处理，操作已取消。")
            return
        
        # 检查是否为灰度图像
        if len(self.image.shape) > 2 and self.image.shape[2] > 1:
            tk.messagebox.showinfo(language_data[self.current_language]['error'], 
                                language_data[self.current_language]['not_grayscale_error'])
            logging.error("尝试对非灰度图像应用移动差分，操作已取消。")
            return
            
        # 创建一个新窗口
        shift_window = tk.Toplevel(self.master)
        shift_window.title(language_data[self.current_language]['shift_difference'])
        shift_window.geometry("600x500")
        shift_window.resizable(False, False)
        
        # 保存原始图像的副本，用于预览
        self.original_image_for_shift = self.image.copy()
        
        # 创建平移滑动条框架
        slider_frame = tk.Frame(shift_window)
        slider_frame.pack(pady=10)
        
        # 创建平移滑动条标签
        tk.Label(slider_frame, text=language_data[self.current_language]['shift_pixels']).pack(side=tk.LEFT, padx=5)
        
        # 创建平移值标签，用于显示当前平移像素数
        shift_value_label = tk.Label(slider_frame, text="0")
        shift_value_label.pack(side=tk.RIGHT, padx=5)
        
        # 创建平移滑动条
        shift_slider = ttk.Scale(
            slider_frame, 
            from_=-3,  # 左移最多3个像素
            to=3,      # 右移最多3个像素
            value=0,   # 初始值为0（不移动）
            length=300,
            orient=tk.HORIZONTAL
        )
        shift_slider.pack(side=tk.LEFT, padx=5)
        
        # 创建预览画布
        preview_canvas = tk.Canvas(shift_window, width=500, height=350)
        preview_canvas.pack(pady=10)
        
        # 创建确认和取消按钮框架
        button_frame = tk.Frame(shift_window)
        button_frame.pack(pady=10)
        
        # 预览图像函数
        def preview_shift(event=None):
            # 获取整数平移值
            shift_pixels = int(shift_slider.get())
            shift_value_label.config(text=str(shift_pixels))
            
            # 使用移动差分函数处理图像
            preview_image = image_transform.shift_difference_edge(self.original_image_for_shift, shift_pixels)
            
            # 显示预览图像
            self._display_image_on_canvas(preview_image, preview_canvas)
        
        # 应用移动差分
        def apply_shift():
            shift_pixels = int(shift_slider.get())
            self.image = image_transform.shift_difference_edge(self.original_image_for_shift, shift_pixels)
            self.display_image()  # 更新主窗口显示
            shift_window.destroy()  # 关闭窗口
            logging.info(f"已应用移动差分边缘检测，平移像素：{shift_pixels}")
        
        # 取消操作
        def cancel_shift():
            shift_window.destroy()  # 关闭窗口
            logging.info("已取消移动差分边缘检测")
          # 滑动条值变化时预览图像
        shift_slider.bind("<Motion>", preview_shift)
        
        # 创建确认和取消按钮
        tk.Button(button_frame, text=language_data[self.current_language]['apply'], command=apply_shift).pack(side=tk.LEFT, padx=10)
        tk.Button(button_frame, text=language_data[self.current_language]['cancel'], command=cancel_shift).pack(side=tk.LEFT, padx=10)
        
        # 初始预览
        preview_shift()
    
    def create_red_mask(self):
        """生成红色掩模并显示"""
        if self.image is None:
            tk.messagebox.showinfo(language_data[self.current_language]['error'], language_data[self.current_language]['no_image_loaded'])
            return

        if self.image.ndim != 3 or self.image.shape[2] < 3:
            tk.messagebox.showinfo(language_data[self.current_language]['error'], language_data[self.current_language]['single_channel_error'])
            return

        # 获取RGB通道
        r, g, b = self.image[:, :, 0], self.image[:, :, 1], self.image[:, :, 2]
        
        # 创建窗口
        dialog = tk.Toplevel(self.master)
        dialog.title(language_data[self.current_language]['red_mask'])
        dialog.minsize(600, 500)  # 设置最小窗口大小
        
        # 创建滑块框架
        sliders_frame = tk.Frame(dialog)
        sliders_frame.pack(pady=10, fill=tk.X)
        
        # 创建阈值滑块
        threshold_frame = tk.Frame(sliders_frame)
        threshold_frame.pack(pady=5, fill=tk.X)
        
        tk.Label(threshold_frame, text=language_data[self.current_language]['mask_threshold'] + ": ").pack(side=tk.LEFT, padx=5)
        threshold_value_label = tk.Label(threshold_frame, text="120")
        threshold_value_label.pack(side=tk.RIGHT, padx=5)
        
        threshold_slider = ttk.Scale(
            threshold_frame,
            from_=0,
            to=255,
            value=120,
            length=300,
            orient=tk.HORIZONTAL
        )
        threshold_slider.pack(side=tk.LEFT, padx=5, fill=tk.X, expand=True)
        
        # 创建强度差异滑块
        intensity_frame = tk.Frame(sliders_frame)
        intensity_frame.pack(pady=5, fill=tk.X)
        
        tk.Label(intensity_frame, text=language_data[self.current_language]['mask_intensity'] + ": ").pack(side=tk.LEFT, padx=5)
        intensity_value_label = tk.Label(intensity_frame, text="30")
        intensity_value_label.pack(side=tk.RIGHT, padx=5)
        
        intensity_slider = ttk.Scale(
            intensity_frame,
            from_=0,
            to=100,
            value=30,
            length=300,
            orient=tk.HORIZONTAL
        )
        intensity_slider.pack(side=tk.LEFT, padx=5, fill=tk.X, expand=True)
        
        # 创建预览画布
        canvas_frame = tk.Frame(dialog)
        canvas_frame.pack(fill=tk.BOTH, expand=True, pady=10)
        
        canvas = tk.Canvas(canvas_frame, width=500, height=350, bg="white")
        canvas.pack(fill=tk.BOTH, expand=True, padx=10)
          # 添加防抖变量
        self.preview_after_id = None
        
        # 预览函数
        def preview_mask(event=None):
            # 获取当前滑块值
            threshold = int(threshold_slider.get())
            intensity = int(intensity_slider.get())
            
            # 更新标签
            threshold_value_label.config(text=str(threshold))
            intensity_value_label.config(text=str(intensity))
            
            # 取消之前的延时更新
            if hasattr(self, 'preview_after_id') and self.preview_after_id:
                dialog.after_cancel(self.preview_after_id)
            
            # 设置新的延时更新（50毫秒后执行，减少频繁更新）
            def delayed_update():
                # 生成掩模
                mask = ((r > threshold) & (r > g + intensity) & (r > b + intensity)).astype(np.uint8) * 255
                
                # 存储掩模作为类属性，便于后续应用
                self.current_mask = mask
                
                # 更新显示
                update_canvas(mask)
                
            self.preview_after_id = dialog.after(50, delayed_update)
            
        # 分离画布更新逻辑
        def update_canvas(mask):
            if mask is None:
                return
            
            # 显示掩模在画布上
            # 适应画布大小
            canvas_width = canvas.winfo_width()
            canvas_height = canvas.winfo_height()
            
            img_height, img_width = mask.shape
            scale = min(canvas_width / img_width, canvas_height / img_height, 1)
            display_width = max(int(img_width * scale), 1)  # 确保至少为1像素
            display_height = max(int(img_height * scale), 1)  # 确保至少为1像素
            
            # 调整掩模图像大小以适应窗口
            pil_mask = Image.fromarray(mask).resize((display_width, display_height), Image.LANCZOS)
            photo = ImageTk.PhotoImage(pil_mask)
            
            # 清空画布并显示新图像
            canvas.delete("all")
            canvas.create_image(
                (canvas_width - display_width) // 2,
                (canvas_height - display_height) // 2,
                anchor=tk.NW,
                image=photo
            )
            canvas.image = photo  # 保持引用
        
        # 保存掩模
        def save_mask():
            save_path = filedialog.asksaveasfilename(defaultextension='.png', filetypes=[('PNG files', '*.png')])
            if save_path:
                Image.fromarray(self.current_mask).save(save_path)
                tk.messagebox.showinfo(language_data[self.current_language]['success'], language_data[self.current_language]['mask_saved'])
                logging.info(f"红色掩模已保存到: {save_path}")
        
        # 绑定滑块事件
        threshold_slider.bind("<ButtonRelease-1>", preview_mask)
        intensity_slider.bind("<ButtonRelease-1>", preview_mask)
        
        # 创建按钮框架
        button_frame = tk.Frame(dialog)
        button_frame.pack(pady=10)
        
        # 预览按钮
        tk.Button(
            button_frame,
            text=language_data[self.current_language]['mask_preview'],
            command=preview_mask
        ).pack(side=tk.LEFT, padx=10)
        
        # 保存按钮
        tk.Button(
            button_frame,
            text=language_data[self.current_language]['save_mask'],
            command=save_mask
        ).pack(side=tk.LEFT, padx=10)
          # 窗口渲染后执行预览
        dialog.update()
        dialog.after(100, preview_mask)  # 延迟100毫秒执行预览，确保窗口已正确渲染
        logging.info("红色掩模生成窗口已打开")
    
    def create_green_mask(self):
        """生成绿色掩模并显示"""
        if self.image is None:
            tk.messagebox.showinfo(language_data[self.current_language]['error'], language_data[self.current_language]['no_image_loaded'])
            return

        if self.image.ndim != 3 or self.image.shape[2] < 3:
            tk.messagebox.showinfo(language_data[self.current_language]['error'], language_data[self.current_language]['single_channel_error'])
            return

        # 获取RGB通道
        r, g, b = self.image[:, :, 0], self.image[:, :, 1], self.image[:, :, 2]
        
        # 创建窗口
        dialog = tk.Toplevel(self.master)
        dialog.title(language_data[self.current_language]['green_mask'])
        dialog.minsize(600, 500)  # 设置最小窗口大小
        
        # 创建滑块框架
        sliders_frame = tk.Frame(dialog)
        sliders_frame.pack(pady=10, fill=tk.X)
        
        # 创建阈值滑块
        threshold_frame = tk.Frame(sliders_frame)
        threshold_frame.pack(pady=5, fill=tk.X)
        
        tk.Label(threshold_frame, text=language_data[self.current_language]['mask_threshold'] + ": ").pack(side=tk.LEFT, padx=5)
        threshold_value_label = tk.Label(threshold_frame, text="120")
        threshold_value_label.pack(side=tk.RIGHT, padx=5)
        
        threshold_slider = ttk.Scale(
            threshold_frame,
            from_=0,
            to=255,
            value=120,
            length=300,
            orient=tk.HORIZONTAL
        )
        threshold_slider.pack(side=tk.LEFT, padx=5, fill=tk.X, expand=True)
        
        # 创建强度差异滑块
        intensity_frame = tk.Frame(sliders_frame)
        intensity_frame.pack(pady=5, fill=tk.X)
        
        tk.Label(intensity_frame, text=language_data[self.current_language]['mask_intensity'] + ": ").pack(side=tk.LEFT, padx=5)
        intensity_value_label = tk.Label(intensity_frame, text="30")
        intensity_value_label.pack(side=tk.RIGHT, padx=5)
        
        intensity_slider = ttk.Scale(
            intensity_frame,
            from_=0,
            to=100,
            value=30,
            length=300,
            orient=tk.HORIZONTAL
        )
        intensity_slider.pack(side=tk.LEFT, padx=5, fill=tk.X, expand=True)
        
        # 创建预览画布
        canvas_frame = tk.Frame(dialog)
        canvas_frame.pack(fill=tk.BOTH, expand=True, pady=10)
        
        canvas = tk.Canvas(canvas_frame, width=500, height=350, bg="white")
        canvas.pack(fill=tk.BOTH, expand=True, padx=10)
          # 添加防抖变量
        self.preview_after_id = None
        
        # 预览函数
        def preview_mask(event=None):
            # 获取当前滑块值
            threshold = int(threshold_slider.get())
            intensity = int(intensity_slider.get())
            
            # 更新标签
            threshold_value_label.config(text=str(threshold))
            intensity_value_label.config(text=str(intensity))
            
            # 取消之前的延时更新
            if hasattr(self, 'preview_after_id') and self.preview_after_id:
                dialog.after_cancel(self.preview_after_id)
            
            # 设置新的延时更新（50毫秒后执行，减少频繁更新）
            def delayed_update():
                # 生成掩模
                mask = ((g > threshold) & (g > r + intensity) & (g > b + intensity)).astype(np.uint8) * 255
                
                # 存储掩模作为类属性，便于后续应用
                self.current_mask = mask
                
                # 更新显示
                update_canvas(mask)
                
            self.preview_after_id = dialog.after(50, delayed_update)
        
        # 分离画布更新逻辑
        def update_canvas(mask):
            # 适应画布大小
            canvas_width = canvas.winfo_width()
            canvas_height = canvas.winfo_height()
            
            img_height, img_width = mask.shape
            scale = min(canvas_width / img_width, canvas_height / img_height, 1)
            display_width = max(int(img_width * scale), 1)  # 确保至少为1像素
            display_height = max(int(img_height * scale), 1)  # 确保至少为1像素
            
            # 调整掩模图像大小以适应窗口
            pil_mask = Image.fromarray(mask).resize((display_width, display_height), Image.LANCZOS)
            photo = ImageTk.PhotoImage(pil_mask)
            
            # 清空画布并显示新图像
            canvas.delete("all")
            canvas.create_image(
                (canvas_width - display_width) // 2,
                (canvas_height - display_height) // 2,
                anchor=tk.NW,
                image=photo
            )
            canvas.image = photo  # 保持引用
        
        # 保存掩模
        def save_mask():
            save_path = filedialog.asksaveasfilename(defaultextension='.png', filetypes=[('PNG files', '*.png')])
            if save_path:
                Image.fromarray(self.current_mask).save(save_path)
                tk.messagebox.showinfo(language_data[self.current_language]['success'], language_data[self.current_language]['mask_saved'])
                logging.info(f"绿色掩模已保存到: {save_path}")
        
        # 绑定滑块事件
        threshold_slider.bind("<ButtonRelease-1>", preview_mask)
        intensity_slider.bind("<ButtonRelease-1>", preview_mask)
        
        # 创建按钮框架
        button_frame = tk.Frame(dialog)
        button_frame.pack(pady=10)
        
        # 预览按钮
        tk.Button(
            button_frame,
            text=language_data[self.current_language]['mask_preview'],
            command=preview_mask
        ).pack(side=tk.LEFT, padx=10)
        
        # 保存按钮
        tk.Button(
            button_frame,
            text=language_data[self.current_language]['save_mask'],
            command=save_mask
        ).pack(side=tk.LEFT, padx=10)
        
        # 窗口渲染后执行预览
        dialog.update()
        dialog.after(100, preview_mask)  # 延迟100毫秒执行预览，确保窗口已正确渲染
        
        logging.info("绿色掩模生成窗口已打开")

    def create_blue_mask(self):
        """生成蓝色掩模并显示"""
        if self.image is None:
            tk.messagebox.showinfo(language_data[self.current_language]['error'], language_data[self.current_language]['no_image_loaded'])
            return
        if self.image.ndim != 3 or self.image.shape[2] < 3:
            tk.messagebox.showinfo(language_data[self.current_language]['error'], language_data[self.current_language]['single_channel_error'])
            return

        # 获取RGB通道
        r, g, b = self.image[:, :, 0], self.image[:, :, 1], self.image[:, :, 2]
        
        # 创建窗口
        dialog = tk.Toplevel(self.master)
        dialog.title(language_data[self.current_language]['blue_mask'])
        dialog.minsize(600, 500)  # 设置最小窗口大小
        
        # 创建滑块框架
        sliders_frame = tk.Frame(dialog)
        sliders_frame.pack(pady=10, fill=tk.X)
        
        # 创建阈值滑块
        threshold_frame = tk.Frame(sliders_frame)
        threshold_frame.pack(pady=5, fill=tk.X)
        
        tk.Label(threshold_frame, text=language_data[self.current_language]['mask_threshold'] + ": ").pack(side=tk.LEFT, padx=5)
        threshold_value_label = tk.Label(threshold_frame, text="120")
        threshold_value_label.pack(side=tk.RIGHT, padx=5)
        
        threshold_slider = ttk.Scale(
            threshold_frame,
            from_=0,
            to=255,
            value=120,
            length=300,
            orient=tk.HORIZONTAL
        )
        threshold_slider.pack(side=tk.LEFT, padx=5, fill=tk.X, expand=True)
        
        # 创建强度差异滑块
        intensity_frame = tk.Frame(sliders_frame)
        intensity_frame.pack(pady=5, fill=tk.X)
        
        tk.Label(intensity_frame, text=language_data[self.current_language]['mask_intensity'] + ": ").pack(side=tk.LEFT, padx=5)
        intensity_value_label = tk.Label(intensity_frame, text="30")
        intensity_value_label.pack(side=tk.RIGHT, padx=5)
        
        intensity_slider = ttk.Scale(
            intensity_frame,
            from_=0,
            to=100,
            value=30,
            length=300,
            orient=tk.HORIZONTAL
        )
        intensity_slider.pack(side=tk.LEFT, padx=5, fill=tk.X, expand=True)
        
        # 创建预览画布
        canvas_frame = tk.Frame(dialog)
        canvas_frame.pack(fill=tk.BOTH, expand=True, pady=10)
        
        canvas = tk.Canvas(canvas_frame, width=500, height=350, bg="white")
        canvas.pack(fill=tk.BOTH, expand=True, padx=10)
          # 添加防抖变量
        self.preview_after_id = None
        
        # 预览函数
        def preview_mask(event=None):
            # 获取当前滑块值
            threshold = int(threshold_slider.get())
            intensity = int(intensity_slider.get())
            
            # 更新标签
            threshold_value_label.config(text=str(threshold))
            intensity_value_label.config(text=str(intensity))
            
            # 取消之前的延时更新
            if hasattr(self, 'preview_after_id') and self.preview_after_id:
                dialog.after_cancel(self.preview_after_id)
            
            # 设置新的延时更新（50毫秒后执行，减少频繁更新）
            def delayed_update():
                # 生成掩模
                mask = ((b > threshold) & (b > r + intensity) & (b > g + intensity)).astype(np.uint8) * 255
                
                # 存储掩模作为类属性，便于后续应用
                self.current_mask = mask
                
                # 更新显示
                update_canvas(mask)
                
            self.preview_after_id = dialog.after(50, delayed_update)
        
        # 分离画布更新逻辑
        def update_canvas(mask):
            # 适应画布大小
            canvas_width = canvas.winfo_width()
            canvas_height = canvas.winfo_height()
            
            img_height, img_width = mask.shape
            scale = min(canvas_width / img_width, canvas_height / img_height, 1)
            display_width = max(int(img_width * scale), 1)  # 确保至少为1像素
            display_height = max(int(img_height * scale), 1)  # 确保至少为1像素
            
            # 调整掩模图像大小以适应窗口
            pil_mask = Image.fromarray(mask).resize((display_width, display_height), Image.LANCZOS)
            photo = ImageTk.PhotoImage(pil_mask)
            
            # 清空画布并显示新图像
            canvas.delete("all")
            canvas.create_image(
                (canvas_width - display_width) // 2,
                (canvas_height - display_height) // 2,
                anchor=tk.NW,
                image=photo
            )
            canvas.image = photo  # 保持引用
        
        # 保存掩模
        def save_mask():
            save_path = filedialog.asksaveasfilename(defaultextension='.png', filetypes=[('PNG files', '*.png')])
            if save_path:
                Image.fromarray(self.current_mask).save(save_path)
                tk.messagebox.showinfo(language_data[self.current_language]['success'], language_data[self.current_language]['mask_saved'])
                logging.info(f"蓝色掩模已保存到: {save_path}")
        
        # 绑定滑块事件
        threshold_slider.bind("<ButtonRelease-1>", preview_mask)
        intensity_slider.bind("<ButtonRelease-1>", preview_mask)
        
        # 创建按钮框架
        button_frame = tk.Frame(dialog)
        button_frame.pack(pady=10)
        
        # 预览按钮
        tk.Button(
            button_frame,
            text=language_data[self.current_language]['mask_preview'],
            command=preview_mask
        ).pack(side=tk.LEFT, padx=10)
        
        # 保存按钮
        tk.Button(
            button_frame,
            text=language_data[self.current_language]['save_mask'],
            command=save_mask
        ).pack(side=tk.LEFT, padx=10)
        
        # 窗口渲染后执行预览
        dialog.update()
        dialog.after(100, preview_mask)  # 延迟100毫秒执行预览，确保窗口已正确渲染
        
        logging.info("蓝色掩模生成窗口已打开")
    
    def _apply_mask_operation(self, operation):
        """应用掩模操作的通用方法"""
        if self.image is None:
            tk.messagebox.showinfo(language_data[self.current_language]['error'], language_data[self.current_language]['no_image_loaded'])
            return
            
        # 选择掩模文件
        mask_path = filedialog.askopenfilename(filetypes=[('PNG files', '*.png'), ('All files', '*.*')])
        if not mask_path:
            return
            
        try:
            # 加载掩模
            mask = image_io.load_image(mask_path, as_gray=True)
            
            # 确保掩模是二值图像
            mask = (mask > 0).astype(np.uint8)
            
            # 保存原始图像
            original_image = self.image.copy()
            
            # 根据操作类型应用掩模
            if operation == 'and':
                # 与运算
                if len(self.image.shape) == 3:  # 彩色图像
                    for c in range(self.image.shape[2]):
                        self.image[:,:,c] = self.image[:,:,c] * mask
                else:  # 灰度图像
                    self.image = self.image * mask
                logging.info("应用与运算掩模")
            
            elif operation == 'not':
                # 非运算
                if len(self.image.shape) == 3:  # 彩色图像
                    for c in range(self.image.shape[2]):
                        self.image[:,:,c] = self.image[:,:,c] * (1 - mask)
                else:  # 灰度图像
                    self.image = self.image * (1 - mask)
                logging.info("应用非运算掩模")
            
            elif operation == 'or':
                # 或运算 (对于图像像素，取两者中较大的值)
                if len(self.image.shape) == 3:  # 彩色图像
                    for c in range(self.image.shape[2]):
                        self.image[:,:,c] = np.maximum(self.image[:,:,c], mask * 255)
                else:  # 灰度图像
                    self.image = np.maximum(self.image, mask * 255)
                logging.info("应用或运算掩模")
            
            elif operation == 'xor':
                # 异或运算
                if len(self.image.shape) == 3:  # 彩色图像
                    for c in range(self.image.shape[2]):
                        self.image[:,:,c] = np.bitwise_xor(self.image[:,:,c].astype(np.uint8), (mask * 255).astype(np.uint8))
                else:  # 灰度图像
                    self.image = np.bitwise_xor(self.image.astype(np.uint8), (mask * 255).astype(np.uint8))
                logging.info("应用异或运算掩模")
            
            # 更新显示
            self.display_image()
            
        except Exception as e:
            tk.messagebox.showerror(language_data[self.current_language]['error'], str(e))
            logging.error(f"应用掩模时出错: {str(e)}")
    
    def apply_mask_and(self):
        """应用与运算掩模"""
        self._apply_mask_operation('and')
    
    def apply_mask_not(self):
        """应用非运算掩模"""
        self._apply_mask_operation('not')
    
    def apply_mask_or(self):
        """应用或运算掩模"""
        self._apply_mask_operation('or')
    
    def apply_mask_xor(self):
        """应用异或运算掩模"""
        self._apply_mask_operation('xor')
        
    def apply_invert_colors(self):
        """应用非运算（反色）处理"""
        if self.image is None:
            tk.messagebox.showinfo(language_data[self.current_language]['error'], language_data[self.current_language]['no_image_loaded'])
            return

        try:
            # 调用image_transform模块中的invert_colors函数进行反色处理
            self.image = image_transform.invert_colors(self.image)
            
            # 显示处理后的图像
            self.display_image()
            logging.info("已成功应用非运算（反色）处理。")
        except Exception as e:
            tk.messagebox.showerror(language_data[self.current_language]['error'], str(e))

# 创建主窗口和应用程序实例
root = tk.Tk()
app = ImageProcessor(root)
root.mainloop()
